<template>
  <div class="app-container">
    <el-row>
      <el-col :span="6" :xs="24">
        <div class="mainbox-left">
          <div class="box-card left-scroll">
            <el-input
              v-model.trim="filterText"
              size="small"
              prefix-icon="el-icon-search"
              placeholder="请输入搜索项"
              maxlength="30"
              style="margin: 16px 0 0 0"
            />
            <div class="left-title" />
            <el-tree
              ref="tree"
              empty-text="暂无数据"
              :style="{ '--lightOpacity': lightTheme }"
              class="left-tree"
              :load="loadNode"
              lazy
              :data="tree"
              :props="defaultProps"
              :default-expand-all="false"
              :expand-on-click-node="false"
              :highlight-current="true"
              :current-node-key="currentKey"
              :filter-node-method="filterNode"
              node-key="id"
              accordion
              :default-expanded-keys="expendData"
              @node-click="handleNodeClick"
              @node-expand="handleNodeExpand"
              @node-collapse="handleNodeCollapse"
              v-loading="treeloading"
            >
              <span class="custom-tree-node" slot-scope="{ node, data }">
                <el-checkbox v-model="data.checked" @change="handleTreeChecked(data, node)" v-if="node.level != 1">
                  {{ node.label }}
                </el-checkbox>
                <span v-else>{{ node.label }}</span>
              </span>
            </el-tree>
          </div>
        </div>
      </el-col>
      <el-col :span="18" :xs="24" style="padding-left: 0px">
        <div class="mainbox" ref="monitorPage">
          <div class="button-box">
            <div>
              <countDownButton ref="countDown" @start="startTime" @end="endRecord" />
              <el-button
                type="primary"
                class="end-record"
                :disabled="disabledEnd"
                @click="endRecord"
              >结束录制</el-button>
              <el-button type="primary" @click="screenshot">截图</el-button>
              <el-button type="primary" @click="fullscreen">{{ fullscreenButton }}</el-button>
            </div>
            <div>
              <label>调整每页显示监控数量</label>
              <el-select v-model="monitorNumber" style="width: 80px; margin: 0 20px">
                <el-option label="1" :value="1"></el-option>
                <el-option label="4" :value="4"></el-option>
                <el-option label="9" :value="9"></el-option>
                <el-option label="16" :value="16"></el-option>
                <!-- <el-option label="25" :value="25"></el-option> -->
              </el-select>
              <el-button type="primary" @click="handleMonitorNum">确定</el-button>
            </div>
          </div>
          <div class="monitor-wrap">
            <div class="monitor-play monitor-9" ref="monitorBox">
              <div class="item" v-for="(item, index) in playList" :key="index"
                   @contextmenu.prevent>
                <!-- <video src="" controls autoplay
                       muted loop>你的浏览器不支持 <code>video</code> 标签。</video> -->
                <video-player class="video-player vjs-custom-skin video-view" ref="videoPlayer" :options="item.options"
                              crossOrigin="anonymous"  @canplay="handleCanplay(item)" @error="handleError(item)"
                              @pause="onPlayerPause($event, index)"></video-player>
                <monitor-error :visible="!item.success" :name="item.label" :code="item.code" />
              </div>
            </div>
          </div>
          <dt-pagination
            v-show="total > pageSize"
            :total="total"
            :page.sync="currentPage"
            :limit.sync="pageSize"
            layout="prev, pager, next"
            @pagination="paginationChange"
          />
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import monitorError from './components/monitorError'
import countDownButton from './components/countDownBtn'
// eslint-disable-next-line import/no-cycle
import { getVideoGroup } from '@/api/videoFusion/videoManage'
import { getList, getPlayUrl, screenImage } from '@/api/videoFusion/monitorGroup'
import { startRecord, stopRecord } from '@/api/monitorPlay/playView'

// 引入样式
import 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css'

const CLASSNAME_MAP = {
  1: 'monitor-1',
  4: 'monitor-4',
  9: 'monitor-9',
  16: 'monitor-16',
  25: 'monitor-25'
}

const options = {
  playbackRates: [], // 可选择的播放速度
  autoplay: true, // 如果true,浏览器准备好时开始回放。
  muted: true, // 默认情况下将会消除任何音频。
  loop: false, // 视频一结束就重新开始。
  preload: 'auto',
  language: 'zh-CN',
  aspectRatio: '16:9',
  sources: [
    {
      type: 'application/x-mpegURL',
      // src: 'http://220.161.87.62:8800/hls/0/index.m3u8'
      src: ''
    }
  ],
  notSupportedMessage: '前方视频信号中断，请稍后再试。',
  controlBar: {
    timeDivider: true, // 当前时间和持续时间的分隔符
    durationDisplay: true, // 显示持续时间
    remainingTimeDisplay: true, // 是否显示剩余时间功能
    fullscreenToggle: true, // 全屏按钮
    playToggle: false
  }
}
let isFirst = true

export default {
  name: 'PlayGroupView',
  components: { monitorError, countDownButton },
  data() {
    return {
      disabledEnd: true,
      countTime: '00:00:00',
      timer: null,
      visible: false,
      monitorNumber: 9,
      pageSize: 9,
      total: 0,
      currentPage: 1,
      fullscreenButton: '全屏',
      filterText: '',
      tree: [],
      currentKey: '',
      treeloading: false,
      defaultProps: {
        children: 'children',
        label: 'label',
        isLeaf: 'leaf'
      },
      expendData: [],
      oldkey: '',
      playList: [],
      playTime: [],
      checkedList: [],
      treeData: [],
      playType: this.$route.query.playType,
      loading: null,
      recordList: []
    }
  },
  computed: {
    lightTheme() {
      return `${this.$store.state.settings.theme}19`
    }
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val)
    }
  },
  mounted() {
    const { groupId, monitorIds } = this.$route.query
    this.currentKey = groupId
    this.oldkey = groupId
    this.checkedList = Array.isArray(monitorIds) ? monitorIds : [monitorIds]
    window.addEventListener('beforeunload', this.handleTabClose)
  },
  beforeDestroy() {
    this.stopRecords()
    this.stopPlay()
    clearInterval(this.timer)
    window.removeEventListener('beforeunload', this.handleTabClose)
  },
  methods: {
    handleTabClose() {
      this.stopRecords()
      this.stopPlay()
    },
    stopRecords() {
      const stopArr = []
      if (this.recordList.length > 0) {
        this.recordList.forEach((id) => {
          stopArr.push(stopRecord(id))
        })
        Promise.all(stopArr).then(() => {
          this.recordList = []
        })
      }
    },
    stopPlay() {
      const stopArr = []
      this.playList.forEach((item) => {
        stopArr.push(stopRecord(item.playId))
      })
      Promise.all(stopArr)
    },
    async loadNode(node, reslove) { // 左侧监控分组, 点击展开获取监控列表
      if (node.level == 0) { // 获取分组列表
        try {
          this.treeloading = true
          const res = await getVideoGroup()
          const treeArr = res.data.map((item) => {
            return {
              label: `${item.groupName}(${item.groupCode})`,
              ...item,
              children: []
            }
          })
          this.expendData = treeArr.length ? [this.currentKey || treeArr[0].id] : []
          this.treeData = treeArr
          this.treeloading = false
          return reslove(treeArr)
        } catch (error) {
          this.treeloading = false
        }
      }
      if (node.level > 0) { // 获取对应分组下的监控列表
        const res = await getList({ groupId: node.data.id, pagpageNo: 1, pageSize: 1000 })
        const treeArr = res.data.rows.map((item) => {
          return {
            label: item.monitorName,
            ...item,
            leaf: true,
            checked: false,
            code: item.monitorCode
          }
        })
        if (isFirst) {
          this.checkedList.forEach((id) => {
            const i = treeArr.findIndex((item) => item.monitorId == id)
            treeArr[i].checked = true
          })
          isFirst = false
          this.setPlayViews(treeArr)
        } else {
          treeArr.forEach((item, i) => {
            if (i < this.pageSize) {
              item.checked = true
            }
          })
          this.setPlayViews(treeArr)
        }
        // this.treeData 当前树形结构的数据项, 初始化时添加进去, 解决上面加载数据 设置选中时 tree 无法拿到监控列表的问题
        const i = this.treeData.findIndex((item) => item.id == node.data.id)
        this.treeData[i].children = treeArr
        return reslove(treeArr)
      }
    },
    onPlayerPause($event, index) { // 禁止暂停(后端实现的截图录制, 暂停视频的话会有问题)
      this.$refs.videoPlayer[index].player.play()
    },
    handleCanplay(row) { // 播放成功回调
      row.success = true
    },
    handleError(row) { // 播放失败回调
      row.success = false
    },
    fullLoading() {
      if (this.loading) {
        this.loading.close()
        this.loading = null
        return
      }
      this.loading = this.$loading({
        lock: true,
        text: '监控数据加载中...',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
    },
    setPlayViews(data, bool) { // 右侧播放区域 添加数据
      if (bool) {
        getPlayUrl({ playType: 2, monitorId: data[0].monitorId, monitorAddr: data[0].monitorAddr }).then((res) => {
          const itemOptions = JSON.parse(JSON.stringify(options))
          itemOptions.notSupportedMessage = '前方视频信号中断，请稍后再试。'
          itemOptions.sources[0].src = res.data.httpPlayUrl
          const obj = {
            ...data[0],
            options: itemOptions,
            success: res.success,
            playId: res.data.id
          }
          setTimeout(() => {
            this.playList.push(obj)
          }, 20000)
        })
        return
      }
      const PromiseArr = []
      this.total = data.length
      const checkedList = data.filter((item) => {
        return item.checked
      })
      this.playList = []
      this.fullLoading()
      checkedList.forEach((item) => {
        PromiseArr.push(getPlayUrl({ playType: 2, monitorId: item.monitorId, monitorAddr: item.monitorAddr }))
      })
      Promise.all(PromiseArr).then((res) => { // 获取播放链接
        setTimeout(() => { // 这个定时器是因为后端 视频流转换需要至少7s的时间
          this.playList = res.map((ret, i) => {
            const itemOptions = JSON.parse(JSON.stringify(options))
            itemOptions.notSupportedMessage = '前方视频信号中断，请稍后再试。'
            itemOptions.sources[0].src = ret.data.httpPlayUrl
            return {
              ...checkedList[i],
              options: itemOptions,
              success: ret.success,
              playId: ret.data.id
            }
          })
          this.fullLoading()
        }, 20000)
      }).catch(() => {
        this.fullLoading()
      })
    },
    handleTreeChecked(data, node) { // 选中监控回调
      if (!data.checked) {
        const index = this.playList.findIndex((item) => item.id == data.id)
        this.playList.splice(index, 1)
        return
      }
      const i = this.treeData.findIndex((item) => item.id == node.parent.data.id)
      if (i > -1) {
        const checkedList = this.treeData[i].children.filter((item) => {
          return item.checked
        })
        this.$nextTick(() => {
          if (checkedList.length > this.pageSize) {
            data.checked = false
            this.$message.warning('不能超出最大的播放数量，如需添加请移除部分播放监控')
          } else {
            const arr = node.parent.data.children
            if (arr.length > 0) {
              this.setPlayViews([data], true)
            } else {
              this.playList = []
            }
          }
        })
      }
    },
    handleNodeExpand(data) { // 点击tree节点展开回调
      if (data.id != this.oldkey) {
        const arr = data.children
        if (arr.length <= 0) {
          return
        }
        this.currentKey = data.id
        this.oldkey = data.id
        this.total = data.children ? data.children.length : 0
        this.resetTreeChecked()
        this.$nextTick(() => {
          arr.forEach((item, i) => {
            if (i < this.pageSize) {
              item.checked = true
            }
          })
          this.setPlayViews(data.children)
        })
      }
    },
    resetTreeChecked() { // 重置选中项
      this.treeData.forEach((item) => {
        item.children.forEach((child) => {
          child.checked = false
        })
      })
    },
    handleNodeCollapse(data) {},
    handleNodeClick(data, node) {},
    filterNode(value, data) { // 筛选节点
      if (!value) return true
      return data.label.indexOf(value) !== -1
    },
    paginationChange(obj) { // 分页
      const data = this.treeData.find((item) => item.id == this.oldkey)
      const startIndex = (obj.page - 1) * this.pageSize
      data.children.forEach((item, index) => {
        if (index >= startIndex && index < (startIndex + this.pageSize)) {
          item.checked = true
        } else {
          item.checked = false
        }
      })
      this.setPlayViews(data.children)
    },
    handleMonitorNum() { // 设置每页多少条
      if (this.pageSize !== this.monitorNumber) {
        Object.values(CLASSNAME_MAP).forEach((className) => {
          this.$refs.monitorBox.classList.remove(className)
        })
        this.$refs.monitorBox.classList.add(CLASSNAME_MAP[this.monitorNumber])
        this.pageSize = this.monitorNumber
        this.currentPage = 1
        this.resetChecked()
      }
    },
    resetChecked() { // 重置选中状态
      const data = this.treeData.find((item) => item.id == this.oldkey)
      data.children.forEach((item, i) => {
        if (i < this.pageSize) {
          item.checked = true
        } else {
          item.checked = false
        }
      })
      this.setPlayViews(data.children)
    },
    endRecord() {
      this.stopRecords()
      this.disabledEnd = true
      this.$refs.countDown.save()
    },
    screenshot() { // 截图
      if (!this.playList.length) {
        return
      }
      const promiseArr = []
      this.playList.forEach((item) => {
        promiseArr.push(screenImage({
          playUrl: item.options.sources[0].src,
          playType: this.playType || 3,
          monitorId: item.monitorId,
          groupId: this.currentKey
        }))
      })
      Promise.all(promiseArr).then((res) => {
        const bool = res.every((item) => item.success)
        if (bool) {
          this.$message({
            message: '截图成功',
            type: 'success'
          })
        } else {
          const nameList = []
          res.forEach((item, i) => {
            if (!item.success) {
              nameList.push(this.playList[i].monitorName)
            }
          })
          this.$message({
            message: `监控${nameList.join('，')} 截图异常`,
            type: 'error'
          })
        }
      })
    },
    // 全屏
    fullscreen() {
      if (this.$refs.monitorPage.className.indexOf('ele-table-fullscreen') > -1) {
        this.$refs.monitorPage.classList.remove('ele-table-fullscreen')
        this.fullscreenButton = '全屏'
      } else {
        this.$refs.monitorPage.classList.add('ele-table-fullscreen')
        this.fullscreenButton = '取消全屏'
      }
    },
    startTime() {
      const promiseArr = []
      this.playList.forEach((item) => {
        promiseArr.push(startRecord({
          playUrl: item.options.sources[0].src,
          playType: this.playType || 3,
          monitorId: item.monitorId,
          groupId: this.currentKey
        }))
      })
      Promise.all(promiseArr).then((res) => {
        const bool = res.every((item) => item.success)
        if (bool) {
          this.$refs.countDown.startTiming()
          this.disabledEnd = false
          res.forEach((item) => {
            this.recordList.push(item.data.id)
          })
        } else {
          const nameList = []
          this.recordList = []
          res.forEach((item, i) => {
            if (!item.success) {
              nameList.push(this.playList[i].monitorName)
            }
          })
          this.$message({
            message: `监控${nameList.join('，')} 录制异常`,
            type: 'error'
          })
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.app-container {
  background-color: #efefef;
  height: 100vh;
  overflow-y: auto;

  .left-scroll {
    overflow: scroll;
    height: calc(100vh - 33px) !important;
  }
}
.app-container .mainbox {
  height: auto;
  background-color: #fff;
  box-shadow: 0px 4px 8px 2px rgba(0, 0, 0, 0.04),
              0px 2px 6px 0px rgba(0, 0, 0, 0.06),
              0px 0px 4px 0px rgba(0, 0, 0, 0.08);
  margin: 16px 17px 17px;
  justify-content: space-between;
}
.left-title {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-bottom: 16px;
}
.button-box {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
// .monitor-wrap {
//   // height: calc(100vh - 159px);
// }
.monitor-play {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  height: 100%;
  .item {
    position: relative;
    box-sizing: border-box;
    .video-view {
      width: 100%;
      height: 100%;
      object-fit: cover;
      // pointer-events: none;
    }
  }
}
.monitor-1 {
  .item {
    width: 100%;
    // height: 100%;
    font-size: 24px;
  }
}
.monitor-4 {
  .item {
    width: 48%;
    // height: 48%;
    font-size: 20px;
    margin-right: 2%;
    margin-bottom: 2%;
  }
  .item:nth-of-type(2n) {
    margin-right: 0;
  }
  .item:nth-of-type(n+3) {
    margin-bottom: 0;
  }
}
.monitor-9 {
  .item {
    width: 32%;
    // height: 32%;
    margin-right: 1%;
    margin-bottom: 1%;
    font-size: 16px;
  }
  .item:nth-of-type(3n) {
    margin-right: 0;
  }
  .item:nth-of-type(n+7) {
    margin-bottom: 0;
  }
}
.monitor-16 {
  .item {
    width: 23%;
    height: 23%;
    margin-right: 1.2%;
    margin-bottom: 1.2%;
    font-size: 16px;
    &:nth-of-type(4n) {
      margin-right: 0;
    }
    &:nth-of-type(n+13) {
      margin-bottom: 0;
    }
  }
}
.monitor-25 {
  .item {
    width: 18%;
    height: 18%;
    margin-right: 1.2%;
    margin-bottom: 1.2%;
    font-size: 14px;
    &:nth-of-type(5n) {
      margin-right: 0;
    }
    &:nth-of-type(n+21) {
      margin-bottom: 0;
    }
  }
}
::v-deep .end-record.is-disabled {
  color: #C0C4CC;
}
.custom-tree-node {
  .el-checkbox {
    margin-right: 5px;
  }
}
.ele-table-fullscreen {
  margin: 0 !important;
  height: 100vh !important;
  .monitor-wrap {
    height: calc(100vh - 129px);
  }
}
</style>
